iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
AI & Data

從Keras框架與數學概念了解機器學習系列 第 12

[從Keras框架與數學概念了解機器學習] - 12. 自定義 Model

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20230912/201446148PQGDdbcjv.jpg

從前面Model的文章可以得知,Model繼承base_layer,代表Model也可以當作Layer使用,可以執行 build與 Call。現在要嘗試自訂義Model類別,讓模型可以多樣性、彈性的宣告。

可以繼承的模型類別有 keras.engine.training.Model、keras.engine.sequential.Sequential、keras.engine.functional、keras.engine.base_layer 等等,不管那種類別,建構模型最重要也最需要實作的事項就是層的查增刪改、建構模型、模型訓練、模型計算框架等等。可以參考 模型執行fit的運作文章。基本上這些類別幾乎都繼承keras.engine.base_layer,所以稱模型也可以是Layer的一種也不為過。而模型類別與層的差異主要在於,模型是類似Container容器般的主導管理層的行為,而層卻是執行細部工作的角色。

模型建構與訓練通常都要經過模型類別與層的call 函式,所以這邊大多是要迭代整個模型來逐一呼叫並做串聯,而都會執行模型實體的 keras.engine.training.Model.step_function函式。所以自定義模型可以實作的重要部分可以是 Call 與 step_function 函式。

再看一次模型類別:
https://ithelp.ithome.com.tw/upload/images/20230912/20144614Rq62ipc8Ph.jpg

第一個範例,自定義模型類別:

自定義Model類別程式

InputsShape = keras.Input(shape=(None,784))

class MyModel(keras.Model):
    def __init__(self,inputs):
        super().__init__()
        dense1_Output = layers.Dense(64, activation="sigmoid")(inputs)
        dense2_Output = layers.Dense(10, activation="softmax")(dense1_Output)
        self.SubModel = keras.Model(inputs, dense2_Output)
        
    def call(self, inputs):
        return self.SubModel(inputs)
        
model = MyModel(inputs = InputsShape)

model.compile(optimizer="rmsprop",
                loss="sparse_categorical_crossentropy",
                metrics=["accuracy"])
                
model.fit(train_images, train_labels)

說明:

  1. create MyModel instance (model = MyModel(inputs = InputsShape) )
    https://ithelp.ithome.com.tw/upload/images/20230912/20144614idjKOA1sMe.jpg

起一個自定義模型類別,因為是繼承 keras.engine.training.Model,初始建構仍會到自身的
MyModel.init ,執行到了以下程式:

self.SubModel = Model(inputs, dense2_Output)

是委派了一個新的 keras.engine.training.Model 類別並指定到 self.SubModel,所以如上圖這部分會接續跑
到橘色區域,如同 Model vs Sequence 文章中 ,產生 Model 實體的敘述。

  1. 執行訓練 fit (model.fit(train_images, train_labels))
    https://ithelp.ithome.com.tw/upload/images/20230912/20144614ksFseU4os6.jpg

執行訓練時,最重要的執行部分是 Train_Step,會從 MyModel.call 執行然後迭代到每層 layer.call,一樣會檢查是否每層都build過產生設定與初始Weight。 由於因為 init 宣告委派了新的keras.engine.training.Model ,以層的呼叫做串聯,代表已經執行過build的動作(參考 Model vs Sequence 文章中初步執行 Layer 設定部分 ),所以 Model.call 接續橘色部分執行 委派的 keras.engine.training.Model.call(inputs) 。 橘色部分的流程,因為已經 build 過,所以會到 keras.engine.functional.Functional._run_internal_graph 逐一迭代執行每層的Layer.call 函式。最後將結果張量傳出去,接續計算loss、更新權重的update_state等動作。

第二個範例,把Model當成Layer,實作它的Call函式去回傳Layer實體,或使用另一個可作初始化的類別,實作__Call__回傳Layer實體也可行。

把Model當成Layer程式:

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.models import Model

class MyLayer(Model):
    def __init__(self):
        super().__init__()
        self.dense = layers.Dense(10, activation="softmax")
    def call(self, inputs):
        return self.dense(inputs)
        
inputs = layers.Input(shape=(None, 784))
features = layers.Dense(64, activation="relu")(inputs)
outputs = MyLayer()(features)

model = tf.keras.Model(inputs=inputs, outputs=outputs)

model.compile(optimizer="rmsprop",
                loss="sparse_categorical_crossentropy",
                metrics=["accuracy"])
                
model.fit(train_images, train_labels)

說明:

這邊自定義一個子類別為 MyModel 並繼承 keras.engine.training.Model,主要實作 call 函式,而 keras.engine.training.Model繼承keras.engine.base_layer。 在模型初始化時,會接收inputs層、 outputs層之參數:

model = keras.Model(inputs=inputs, outputs=outputs)

而傳入參數特別是 outputs,是用自定義類別回傳的;此自定義類別 MyModel 初始化時先建立一個 Dense 層,於MyModel.call 函式 利用此Dense層的 call函式接收額外串接好的層,利用 Dense.call 將所有的層串聯起來(可參考Model vs Sequence之文設定layer的另一種方式),並回傳供給keras.Model使用。

所以在 MyModel之 init 至 call 最後回傳前,可以實行一些 層的設定、輸入資料的處理preprocess動作。

以上是自定義模組的範例,可以透過運作了解未來可以擴充或額外執行那些動作,與執行的時機。


上一篇
[從Keras框架與數學概念了解機器學習] - 11. Model.fit vs Sequence.fit
下一篇
[從Keras框架與數學概念了解機器學習] - 13. 自訂義 Layer
系列文
從Keras框架與數學概念了解機器學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言